package mvc.core.impl;

import java.awt.Image;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;

import mvc.core.IMachuPicchu;
import mvc.effects.IEffect;
import mvc.image.MachuImage;
import mvc.imageProcessor.impl.ImageProcessor;
import mvc.utils.FileErrorException;
import mvc.utils.FileUtilitys;
import mvc.utils.MPResourceBundle;

import com.google.inject.Guice;
import com.google.inject.Injector;

/**
 * The core of MachuPicchu.
 * 
 * @author Joel
 * 
 */

public class MachuPicchu implements IMachuPicchu {
	private Injector injector;
	private ImportHandler importHandler;
	private ExportHandler exportHandler;
	private ImageProcessor imageProcessor;
	private String uniqueRuntimePath;
	private EffectsHandler effectsHandler;
	private LibraryHandler libraryHandler;
	private ResourceBundle messages;
	private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);

	private MachuPicchu() {
		injector = Guice.createInjector(new MPModule());
		importHandler = injector.getInstance(ImportHandler.class);
		exportHandler = injector.getInstance(ExportHandler.class);
		libraryHandler = injector.getInstance(LibraryHandler.class);
		effectsHandler = new EffectsHandler();
		imageProcessor = new ImageProcessor();
		pcs.firePropertyChange("imageListChanged", null, null); //$NON-NLS-1$
		messages = MPResourceBundle.getResourceBundle();

		uniqueRuntimePath = "MachuPicchu_" + System.currentTimeMillis() //$NON-NLS-1$
				+ File.separator;

	}

	private static class MachuPicchuHolder {
		private static final MachuPicchu INSTANCE = new MachuPicchu();
	}

	/**
	 * Returns the instance of MachuPicchu currently in use. Follows the
	 * singleton-pattern.
	 * 
	 * @return
	 */
	public static MachuPicchu getInstance() {
		return MachuPicchuHolder.INSTANCE;
	}

	@Override
	public void exportImages() {
		try {
			exportHandler.exportImages(libraryHandler.getSelectedImages());
		} catch (IOException e) {
			pcs.firePropertyChange(
					"errorDialog", null, messages.getString("SaveError")); //$NON-NLS-1$ //$NON-NLS-2$
		} catch (FileErrorException e) {
			pcs
					.firePropertyChange(
							"errorDialog", null, messages.getString("errorWith") + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
		}
		pcs.firePropertyChange("imageListChanged", null, null); //$NON-NLS-1$
	}

	@Override
	public List<MachuImage> getImageList() {
		return libraryHandler.getImages();
	}

	@Override
	public void importImages(int width, int height) {
		try {
			List<MachuImage> importedImages = importHandler
					.getImages(uniqueRuntimePath);
			importedImages = testImages(importedImages);
			if (importedImages.size() > 0) {
				libraryHandler.addImages(importedImages);
				for (MachuImage image : importedImages) {
					image.setThumbnail(imageProcessor.createThumbnail(image,
							width, height));
				}
				pcs.firePropertyChange("imageListChanged", null, null); //$NON-NLS-1$
				setSelectedImages(importedImages);
			}
		} catch (IOException e) { // TODO
			pcs.firePropertyChange(
					"errorDialog", null, messages.getString("DirError")); //$NON-NLS-1$ //$NON-NLS-2$
		} catch (FileErrorException e) {
			pcs
					.firePropertyChange(
							"errorDialog", null, messages.getString("errorWith") + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
		}

	}

	@Override
	public void addPropertyChangeListener(PropertyChangeListener l) {
		pcs.addPropertyChangeListener(l);

	}

	@Override
	public void removePropertyChangeListener(PropertyChangeListener l) {
		pcs.removePropertyChangeListener(l);

	}

	@Override
	public void removeImage(List<MachuImage> list) {
		libraryHandler.removeImages(list);
		pcs.firePropertyChange("imageListChanged", null, null); //$NON-NLS-1$
		pcs.firePropertyChange("selectedImagesChanged", null, null); //$NON-NLS-1$
	}

	@Override
	public List<MachuImage> getSelectedImages() {
		return libraryHandler.getSelectedImages();
	}

	@Override
	public void setSelectedImages(List<MachuImage> list) {

		libraryHandler.setSelectedImages(testImages(list));
		pcs.firePropertyChange("selectedImagesChanged", null, null); //$NON-NLS-1$
	}

	@Override
	public void applyEffect(IEffect effect) {

		List<MachuImage> selectedImages = libraryHandler.getSelectedImages();
		effectsHandler.addEffect(selectedImages, effect);
		imageProcessor.processThumbnailImages(selectedImages);

		pcs.firePropertyChange("imageListChanged", null, null); //$NON-NLS-1$
		pcs.firePropertyChange("selectedImagesChanged", null, null);//$NON-NLS-1$
	}

	@Override
	public List<IEffect> getListWithEffects() {

		return effectsHandler.getListWithEffects();
	}

	/**
	 * Performs a controlled shutdown of the application.
	 */
	@Override
	public void shutdown() {

		FileUtilitys.removeFileDirectory(uniqueRuntimePath);
	}

	@Override
	public Image getScaledImage(Image img, int width, int height) {
		try {
			return imageProcessor.createScaledImage(img, width, height);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;

	}

	@Override
	public Image processImage(MachuImage mi, int width, int height) {
		try {
			return imageProcessor.processImage(mi, width, height);
		} catch (IOException e) {
			libraryHandler.removeImage(mi);
			pcs
					.firePropertyChange(
							"errorDialog", null, messages.getString("errorWith") + mi.getFile().getName()); //$NON-NLS-1$ //$NON-NLS-2$
		} catch (FileErrorException e) {
			libraryHandler.removeImage(mi);
			pcs
					.firePropertyChange(
							"errorDialog", null, messages.getString("errorWith") + mi.getFile().getName()); //$NON-NLS-1$ //$NON-NLS-2$
		}
		return null;
	}

	@Override
	public Image getFullSizeImage(MachuImage img) {
		try {
			Image im = imageProcessor.getFullSizeImage(img);
			return im;
		} catch (IOException e) {
			libraryHandler.removeImage(img);
			pcs
					.firePropertyChange(
							"errorDialog", null, messages.getString("errorWith") + img.getFile().getName()); //$NON-NLS-1$ //$NON-NLS-2$
		} catch (FileErrorException e) {
			libraryHandler.removeImage(img);
			pcs
					.firePropertyChange(
							"errorDialog", null, messages.getString("errorWith") + img.getFile().getName()); //$NON-NLS-1$ //$NON-NLS-2$
		}
		return null;

	}

	@Override
	public void updateMainStageImage(int thumbnailWidth, int thumbnailHeight) {
		MachuImage img = getSelectedImages().get(0);
		try {
			img.setThumbnail(imageProcessor.createThumbnail(img,
					thumbnailWidth, thumbnailHeight));
		} catch (IOException e) {
			libraryHandler.removeImage(img);
			pcs
					.firePropertyChange(
							"errorDialog", null, messages.getString("errorWith") + img.getFile().getName()); //$NON-NLS-1$ //$NON-NLS-2$
			e.printStackTrace();
		} catch (FileErrorException e) {
			libraryHandler.removeImage(img);
			pcs
					.firePropertyChange(
							"errorDialog", null, messages.getString("errorWith") + img.getFile().getName()); //$NON-NLS-1$ //$NON-NLS-2$
		}

		pcs.firePropertyChange("selectedImagesChanged", null, null); //$NON-NLS-1$
		pcs.firePropertyChange("imageListChanged", null, null); //$NON-NLS-1$
	}

	@Override
	public void addToSelectedImages(MachuImage i) {
		libraryHandler.addToSelectedImages(i);
		pcs.firePropertyChange("selectedImagesChanged", null, null); //$NON-NLS-1$

	}

	@Override
	public Locale getLanguageOfApplication() {
		return MPResourceBundle.getResourceBundle().getLocale();
	}

	@Override
	public void setLanguageOfApplication(Locale currentLocale) {
		MPResourceBundle.setResourceBundle(currentLocale);
		pcs.firePropertyChange("languageChanged", null, MPResourceBundle //$NON-NLS-1$
				.getResourceBundle().getLocale());
	}

	@Override
	public List<MachuImage> testImages(List<MachuImage> list) {
		for (int i = list.size() - 1; i >= 0; i--) {
			String filename = list.get(i).getFile().getName();
			try {
				imageProcessor.getFullSizeImage(list.get(i));
			} catch (IOException e) {
				list.remove(i);
				pcs
						.firePropertyChange(
								"errorDialog", null, messages.getString("errorWith") + filename); //$NON-NLS-1$ //$NON-NLS-2$

			} catch (FileErrorException e) {
				list.remove(i);
				pcs
						.firePropertyChange(
								"errorDialog", null, messages.getString("errorWith") + filename); //$NON-NLS-1$ //$NON-NLS-2$

			}
		}
		return list;
	}

}
